﻿// Note: This source code includes code from the MVVM tutorial
// at http://msdn.microsoft.com/en-us/magazine/dd419663.aspx
using System;
using System.Net;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Documents;
using System.Windows.Ink;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Animation;
using System.Windows.Shapes;
using System.Collections.ObjectModel;
using System.ServiceModel;
using WPF_GUI.ServiceAgents;
using System.Diagnostics;
using WPF_GUI.AirportSVC;
using System.Collections.Generic;
using System.Windows.Data;
using WPF_GUI;
using WPF_GUI.Commanding;
using WPF_GUI.Converters;
using System.Linq;
using System.Collections.Specialized;

namespace WPF_GUI.ViewModels
{
    public class MainPageViewModel : ViewModelBase, IAirportServiceCallback
    {
        // Constants
        public const int _runwayId24L = 0;
        public const int _runwayId24R = 1;
        public const int _runwayId25L = 2;
        public const int _runwayId25R = 3;
        public const int _runwayId6R = 4;
        public const int _runwayId6L = 5;
        public const int _runwayId7R = 6;
        public const int _runwayId7L = 7;
        public const int _gateIdD7 = 8;
        public const int _gateIdD8 = 9;
        public const int _gateIdD9 = 10;
        public const int _gateIdD10 = 11;
        public const int _gateIdC6 = 12;
        public const int _gateIdC7 = 13;
        public const int _gateIdC8 = 14;
        public const int _gateIdC9 = 15;
        public const int _gateIdC10 = 16;

        private Dictionary<Node, string> _nodeToSurfaceName;
        private Dictionary<string, Node> _surfaceNameToNode;
        
        private Plane _selectedPlane;
        private Node _selectedDestinationNode;
        private Map _airportMap;                
        private ObservableCollection<Route> _displayedRoutes;
        private ObservableCollection<PathGeometry> _selectedRoutesPathGeometries = new ObservableCollection<PathGeometry>();
        private bool _selectedPlaneIconVisibility = false;
        private bool _routeInformationVisibility;
        private bool _mitigationPanelVisibility;
        private bool _displayedIncursionNodeVisibility = false;
        private bool _runwaySelectionPanelVisibility = false;
        private bool _commandSelectionPanelVisibility = false;
        private bool _suggestionInformationBoxVisibility = false;
        private List<Scenario> _airportScenarios;
        private string _displayedSuggestionText = "";

        private ObservableCollection<Node> _runwayNodes = new ObservableCollection<Node>();       
        private ObservableCollection<PathGeometry> _runwayPathGeometries = new ObservableCollection<PathGeometry>();

        private ObservableCollection<Node> _taxiwayNodes = new ObservableCollection<Node>();
        private ObservableCollection<PathGeometry> _taxiwayPathGeometries = new ObservableCollection<PathGeometry>();

        private ObservableCollection<Node> _gateNodes = new ObservableCollection<Node>();
        private ObservableCollection<Plane> _activePlaneList = new ObservableCollection<Plane>();

        private ObservableCollection<Incursion> _incursionList = new ObservableCollection<Incursion>();
        private Incursion _displayedIncursion;
        private List<Mitigation> _displayedMitigations;

        // AirportServiceClient-related variables
        private InstanceContext _site;
        private AirportServiceClient _airportSvcClient;  

        // Clock
        Clock _displayClock;

        #region Child Windows

        // Manual Route Entry Window
        Window _manualRouteWindow;
        ManualRouteWindowViewModel _manualRouteWindowViewModel;

        // Airport Scenario Selection Window
        Window _loadScenarioWindow;
        LoadScenarioWindowViewModel _loadScenarioWindowViewModel;

        // Manual Control Window
        Window _manualControlWindow;
        ManualControlWindowViewModel _manualControlWindowViewModel;


        // Displayed Route Window
        Window _displayedRouteWindow;
        DisplayedRouteWindowViewModel _displayedRouteWindowViewModel;

        #endregion // Child Windows

        public MainPageViewModel()
        {
            if (!IsDesignTime)
            {
                /*
                // DEBUGGING
                Debug.WriteLine("Runway 24R");
                for (int y = 42; y <= 106; y++)
                {
                    for (int x = 618; x >= 105; x--)
                    {
                        double m = (42.0 - 106.0) / (618.0 - 105.0);
                        double lhs = y - 106.0;
                        double rhs = m * (x - 105.0);
                        
                        Debug.WriteLineIf(Math.Round(lhs, MidpointRounding.AwayFromZero) == Math.Round(rhs, MidpointRounding.AwayFromZero), "(" + x + ", " + y + ")");
                    }
                }
                Debug.Write("\n");

                Debug.WriteLine("Runway 25L");
                for (int y = 359; y <= 437; y++)
                {
                    for (int x = 959; x >= 323; x--)
                    {
                        double m = (359.0 - 437.0) / (959.0 - 323.0);
                        double lhs = y - 437.0;
                        double rhs = m * (x - 323.0);

                        Debug.WriteLineIf(Math.Round(lhs, MidpointRounding.AwayFromZero) == Math.Round(rhs, MidpointRounding.AwayFromZero), "(" + x + ", " + y + ")");
                    }
                }
                Debug.Write("\n");

                Debug.WriteLine("Runway 25R");
                for (int y = 306; y <= 390; y++)
                {
                    for (int x = 1012; x >= 317; x--)
                    {
                        double m = (306.0 - 390.0) / (1012.0 - 317.0);
                        double lhs = y - 390.0;
                        double rhs = m * (x - 317.0);

                        Debug.WriteLineIf(Math.Round(lhs, MidpointRounding.AwayFromZero) == Math.Round(rhs, MidpointRounding.AwayFromZero), "(" + x + ", " + y + ")");
                    }
                }
                Debug.Write("\n");
                */

                // Hide Runway Selection panel on startup
                _runwaySelectionPanelVisibility = false;
                // Hide Mitigation panel on startup
                _mitigationPanelVisibility = false;

                // Hide Warning border around incursion pane
                _incursionPresent = false;
                _incursionList.CollectionChanged += OnIncursionListChanged;

                DisplayClock = new Clock();
                _site = new InstanceContext(this);
                _airportSvcClient = new AirportServiceClient(_site, "NetTcpBinding_IAirportService");                

                // Get airport map from Airport Service
                GetAirportLayout();
                //GetCurrentPlaneList();
                //GetScenarioList();
                RegisterForPlaneUpdates();
                RegisterForIncursionDetectedUpdates();

                // Initialize Manual Control Window
                _manualControlWindowViewModel = new ManualControlWindowViewModel(this);
                _manualControlWindow = new ManualControlWindow();
                _manualControlWindowViewModel.RequestClose += (s, e) => _manualControlWindow.Close();

                _manualControlWindow.DataContext = _manualControlWindowViewModel;

                // Get Scenarios
                GetScenarioList();

                // Initialize Displayed Route Window
                _displayedRouteWindowViewModel = new DisplayedRouteWindowViewModel(this);
                _displayedRouteWindow = new DisplayedRouteWindow();
                _displayedRouteWindowViewModel.RequestClose += (s, e) => _displayedRouteWindow.Close();
                _displayedRouteWindow.DataContext = _displayedRouteWindowViewModel;

                // Show Manual Control Window
                _manualControlWindow.Show();
                // Show Displayed Route Window
                //_displayedRouteWindow.Show();
            }
            else
            {
                _runwaySelectionPanelVisibility = true;
            }

            // Initialize Lists of Surface Name to Node Conversions
            InitializeSurfaceNameLists();
        }
        
        ~MainPageViewModel()
        {
            if (!IsDesignTime)
            {
                UnregisterForPlaneUpdates();
                UnregisterForIncursionDetectedUpdates();
            }
        }        

        #region MainPageViewModel Properties

        public Clock DisplayClock
        {
            get
            {
                return _displayClock;
            }

            set
            {
                if (_displayClock != value)
                {
                    _displayClock = value;
                    //_displayClock.PropertyChanged += (s, e) => OnClockTick();
                    OnPropertyChanged("DisplayClock");
                }
            }
        }
        /*
        private void OnClockTick()
        {
            if (_displayedRoutes != null && _displayedRoutes.Count > 0)
            {
                
                DisplayedSuggestionCountdown = _displayedRoutes[0].StartTime - DateTime.Now;
            }
        }
        */
        public Map AirportMap
        {
            get { return _airportMap; }

            set
            {
                if (_airportMap != value)
                {
                    _airportMap = value;
                    OnPropertyChanged("AirportMap");
                }
            }
        }

        public bool SelectedPlaneIconVisibility
        {
            get
            {
                return _selectedPlaneIconVisibility;
            }

            set
            {
                if (_selectedPlaneIconVisibility != value)
                {
                    _selectedPlaneIconVisibility = value;
                    OnPropertyChanged("SelectedPlaneIconVisibility");
                }
            }
        }

        public bool RouteInformationVisibility
        {
            get
            {
                return _routeInformationVisibility;
            }

            set
            {
                if (_routeInformationVisibility != value)
                {
                    _routeInformationVisibility = value;
                    OnPropertyChanged("RouteInformationVisibility");
                }
            }
        }

        public bool MitigationPanelVisibility
        {
            get
            {
                return _mitigationPanelVisibility;
            }

            set
            {
                if (_mitigationPanelVisibility != value)
                {
                    _mitigationPanelVisibility = value;
                    OnPropertyChanged("MitigationPanelVisibility");
                }
            }
        }

        public bool SuggestionInformationBoxVisibility
        {
            get
            {
                return _suggestionInformationBoxVisibility;
            }

            set
            {
                if (_suggestionInformationBoxVisibility != value)
                {
                    _suggestionInformationBoxVisibility = value;
                    OnPropertyChanged("SuggestionInformationBoxVisibility");
                }
            }
        }

        public bool RunwaySelectionPanelVisibility
        {
            get
            {
                return _runwaySelectionPanelVisibility;
            }

            set
            {
                if (_runwaySelectionPanelVisibility != value)
                {
                    _runwaySelectionPanelVisibility = value;
                    OnPropertyChanged("RunwaySelectionPanelVisibility");
                }
            }
        }

        public bool CommandSelectionPanelVisibility
        {
            get
            {
                return _commandSelectionPanelVisibility;
            }

            set
            {
                if (_commandSelectionPanelVisibility != value)
                {
                    _commandSelectionPanelVisibility = value;
                    OnPropertyChanged("CommandSelectionPanelVisibility");
                }
            }
        }

        // Nodes to be overlayed on the map
        public ObservableCollection<Node> RunwayNodes
        {
            get { return _runwayNodes; }

            set
            {
                if (_runwayNodes != value)
                {
                    _runwayNodes = value;
                    OnPropertyChanged("RunwayNodes");
                }
            }
        }
       
        public ObservableCollection<PathGeometry> RunwayPathGeometries
        {
            get { return _runwayPathGeometries; }

            set
            {
                if (_runwayPathGeometries != value)
                {
                    _runwayPathGeometries = value;
                    OnPropertyChanged("RunwayPathGeometries");
                }
            }
        }        

        public ObservableCollection<PathGeometry> TaxiwayPathGeometries
        {
            get { return _taxiwayPathGeometries; }

            set
            {
                if (_taxiwayPathGeometries != value)
                {
                    _taxiwayPathGeometries = value;
                    OnPropertyChanged("TaxiwayPathGeometries");
                }
            }
        }

        public ObservableCollection<Node> TaxiwayNodes
        {
            get { return _taxiwayNodes; }

            set
            {
                if (_taxiwayNodes != value)
                {
                    _taxiwayNodes = value;
                    OnPropertyChanged("TaxiwayNodes");
                }
            }
        }

        public ObservableCollection<Node> GateNodes
        {
            get { return _gateNodes; }

            set
            {
                if (_gateNodes != value)
                {
                    _gateNodes = value;
                    OnPropertyChanged("GateNodes");
                }
            }
        }
        
        public ObservableCollection<Plane> ActivePlaneList
        {
            get { return _activePlaneList; }

            set
            {
                if (_activePlaneList != value)
                {
                    _activePlaneList = value;
                    OnPropertyChanged("ActivePlaneList");
                }
            }
        }

        public ObservableCollection<Incursion> IncursionList
        {
            get { return _incursionList; }

            set
            {
                if (_incursionList != value)
                {
                    _incursionList = value;
                    _incursionList.CollectionChanged += OnIncursionListChanged;
                    OnPropertyChanged("IncursionList");
                }
            }
        }

        private bool _incursionPresent;
        /// <summary>
        /// Indicates whether IncursionList is empty or not.
        /// </summary>
        public bool IncursionPresent 
        {
            get
            {
                return _incursionPresent;
            }

            set
            {
                if (_incursionPresent != value)
                {
                    _incursionPresent = value;
                    OnPropertyChanged("IncursionPresent");
                }
            }
        }

        private void OnIncursionListChanged(object sender, NotifyCollectionChangedEventArgs e)
        {
            if (_incursionList != null && _incursionList.Count > 0)
            {
                IncursionPresent = true;
                CommandSelectionPanelVisibility = false;
                MitigationPanelVisibility = true;
                DisplayedIncursion = _incursionList.Last();
            }
            else
            {
                IncursionPresent = false;
                MitigationPanelVisibility = false;
            }
        }

        public Plane SelectedPlane
        {
            get
            {
                return _selectedPlane;
            }

            set
            {
                if (_selectedPlane != value)
                {                    
                    _selectedPlane = value;

                    if (_selectedPlane != null)
                    {
                        ObservableCollection<Route> selectedPlaneRoute = new ObservableCollection<Route>();
                        if (_selectedPlane.CurrentRoute != null)
                        {
                            // Display the Route without the already-traversed RouteNodes
                            Route partialRoute = _selectedPlane.CurrentRoute;
                            int startIndex;

                            if (_selectedPlane.NextRouteNodeIndex > 0)
                            {
                                startIndex = _selectedPlane.NextRouteNodeIndex - 1;
                            }
                            else
                            {
                                startIndex = 0;
                            }

                            int count = _selectedPlane.CurrentRoute.RouteNodes.Count - startIndex;

                            if (_selectedPlane.CurrentRoute.RouteNodes.Count > 0)
                            {
                                partialRoute.RouteNodes = _selectedPlane.CurrentRoute.RouteNodes.GetRange(startIndex, count);
                            }

                            //selectedPlaneRoute.Add(_selectedPlane.CurrentRoute);
                            selectedPlaneRoute.Add(partialRoute);

                            // Enable Cancel Route button
                            _manualControlWindowViewModel.CanCancelRoute = true;
                        }
                        else
                        {
                            // Disable Cancel Route button
                            _manualControlWindowViewModel.CanCancelRoute = false;
                        }

                        DisplayedRoutes = selectedPlaneRoute;

                        SelectedDestinationNode = _selectedPlane.DestinationNode;

                        // Turn off Incursion Point display
                        DisplayedIncursionNodeVisibility = false;
                        // Turn off Mitigation panel
                        MitigationPanelVisibility = false;
                        // Turn off Suggestion Box
                        SuggestionInformationBoxVisibility = false;

                        // Turn off displayed Incursion
                        DisplayedIncursion = null;

                        if (_selectedPlane.Status == PlaneStatus.LinedUpAndWaiting)
                        {
                            // Hide Runway Selection Panel
                            RunwaySelectionPanelVisibility = false;
                            // Hide Mitigation Panel
                            MitigationPanelVisibility = false;
                            // Show Command Selection Panel
                            CommandSelectionPanelVisibility = true;
                            // Enable Takeoff Button
                            CanSelectTakeoff = true;
                        }
                        else
                        {
                            // Hide Command Selection Panel
                            CommandSelectionPanelVisibility = false;
                            // Show Runway Selection Panel
                            RunwaySelectionPanelVisibility = true;

                            // Enable Runway Buttons
                            CanSelect24L = true;
                            CanSelect24R = true;
                            CanSelect25L = true;
                            CanSelect25R = true;
                            CanSelect6L = true;
                            CanSelect6R = true;
                            CanSelect7L = true;
                            CanSelect7R = true;

                            // Enable Taxi to Gate Button
                            CanSelectTaxiToGate = true;
                        }
                        SelectedPlaneIconVisibility = true;
                        
                        _manualControlWindowViewModel.CanOpenManualRouteWindow = true;
                    }
                    else
                    {
                        // Disable Runway Buttons
                        CanSelect24L = false;
                        CanSelect24R = false;
                        CanSelect25L = false;
                        CanSelect25R = false;
                        CanSelect6L = false;
                        CanSelect6R = false;
                        CanSelect7L = false;
                        CanSelect7R = false;

                        // Disable Taxi to Gate Button
                        CanSelectTaxiToGate = false;

                        // Hide Selected Plane Icon
                        SelectedPlaneIconVisibility = false;
                        _manualControlWindowViewModel.CanOpenManualRouteWindow = false;
                    }

                    OnPropertyChanged("SelectedPlane");
                }
                
            }
        }

        public Node SelectedDestinationNode
        {
            get
            {
                return _selectedDestinationNode;
            }

            set
            {
                if (_selectedDestinationNode != value)
                {
                    _selectedDestinationNode = value;
                    OnPropertyChanged("SelectedDestinationNode");
                }
            }
        }
        
        public ObservableCollection<Route> DisplayedRoutes
        {
            get
            {
                return _displayedRoutes;
            }

            set
            {
                if (_displayedRoutes != value)
                {
                    _displayedRoutes = value;

                    if (_displayedRoutes != null)
                    {
                        ObservableCollection<PathGeometry> routePathGeometries = new ObservableCollection<PathGeometry>();

                        foreach (Route route in _displayedRoutes)
                        {
                            if (route.RouteNodes.Count > 0)
                            {
                                PathGeometry routePathGeometry = new PathGeometry();
                                PathFigure displayedRoutePathFigure = new PathFigure();
                                PathFigureCollection displayedRoutePathFigureCollection = new PathFigureCollection();
                                PathSegmentCollection displayedRoutePathSegmentCollection = new PathSegmentCollection();
                                List<RouteNode> displayedRouteNodes = route.RouteNodes;
                                
                                int startX = route.StartPoint.X;
                                int startY = route.StartPoint.Y;

                                displayedRoutePathFigure.StartPoint = new System.Windows.Point(startX, startY);

                                for (int i = 1; i < displayedRouteNodes.Count; i++)
                                {
                                    LineSegment lineSegment = new LineSegment();
                                    lineSegment.Point = new System.Windows.Point(displayedRouteNodes[i].XPos, displayedRouteNodes[i].YPos);

                                    displayedRoutePathSegmentCollection.Add(lineSegment);
                                }

                                displayedRoutePathFigure.Segments = displayedRoutePathSegmentCollection;

                                displayedRoutePathFigureCollection.Add(displayedRoutePathFigure);

                                routePathGeometry.Figures = displayedRoutePathFigureCollection;
                                routePathGeometries.Add(routePathGeometry);
                            }
                            /*
                            else
                            {
                                SelectedRoutesPathGeometries.Figures = new PathFigureCollection();
                            }
                            */
                        }
                        SelectedRoutesPathGeometries = routePathGeometries;
                    }
                    OnPropertyChanged("DisplayedRoutes");

                    //RunwaySelectionPanelVisibility = true;
                }
            }
        }

        public ObservableCollection<PathGeometry> SelectedRoutesPathGeometries
        {
            get
            {
                return _selectedRoutesPathGeometries;
            }

            set
            {
                if (_selectedRoutesPathGeometries != value)
                {
                    _selectedRoutesPathGeometries = value;
                    OnPropertyChanged("SelectedRoutesPathGeometries");
                }
            }
        }

        public Incursion DisplayedIncursion
        {
            get
            {
                return _displayedIncursion;
            }

            set
            {
                if (_displayedIncursion != value)
                {
                    _displayedIncursion = value;

                    if (_displayedIncursion != null)
                    {
                        ObservableCollection<Route> incursionRoutes = new ObservableCollection<Route>();

                        foreach (Route route in _displayedIncursion.IncursionRoutes)
                        {
                            incursionRoutes.Add(route);
                        }

                        DisplayedRoutes = incursionRoutes;
                        
                        DisplayedIncursionNodeVisibility = true;

                        // Set DisplayedMitigations to this Incursion's Mitigations
                        DisplayedMitigations = _displayedIncursion.Mitigations;

                        // Turn off SelectedPlane
                        SelectedPlane = null;

                        // Make Runway Selection Pane invisible to display mitigated route suggestions
                        RunwaySelectionPanelVisibility = false;
                        CommandSelectionPanelVisibility = false;
                        MitigationPanelVisibility = true;
                        SuggestionInformationBoxVisibility = false;
                    }
                    else
                    {
                        DisplayedIncursionNodeVisibility = false;
                    }
                   
                    OnPropertyChanged("DisplayedIncursion");
                }
            }
        }

        public List<Mitigation> DisplayedMitigations
        {
            get
            {
                return _displayedMitigations;
            }

            set
            {
                if (_displayedMitigations != value)
                {
                    _displayedMitigations = value;
                    OnPropertyChanged("DisplayedMitigations");
                }
            }
        }

        public bool DisplayedIncursionNodeVisibility
        {
            get
            {
                return _displayedIncursionNodeVisibility;
            }

            set
            {
                if (_displayedIncursionNodeVisibility != value)
                {
                    _displayedIncursionNodeVisibility = value;

                    OnPropertyChanged("DisplayedIncursionNodeVisibility");
                }
            }
        }
        /*
        public TimeSpan DisplayedSuggestionCountdown
        {
            get
            {
                return _displayedSuggestionCountdown;
            }

            set
            {
                if (_displayedSuggestionCountdown != value)
                {
                    _displayedSuggestionCountdown = value;
                    OnPropertyChanged("DisplayedSuggestionCountdown");
                }
            }
        }
        */
        public string DisplayedSuggestionText
        {
            get
            {
                return _displayedSuggestionText;
            }

            set
            {
                if (_displayedSuggestionText != value)
                {
                    _displayedSuggestionText = value;
                    OnPropertyChanged("DisplayedSuggestionText");
                }
            }
        }

        public List<string> CurrentManualRouteString { get; set; }

        public List<Scenario> AirportScenarios
        {
            get
            {
                return _airportScenarios;
            }

            set
            {
                if (_airportScenarios != value)
                {
                    _airportScenarios = value;
                }
            }
        }

        #endregion

        #region Buttons        

        #region Fields

        // Commands
        RelayCommand _setRunway24LCommand;
        RelayCommand _setRunway24RCommand;
        RelayCommand _setRunway25LCommand;
        RelayCommand _setRunway25RCommand;
        RelayCommand _setRunway6LCommand;
        RelayCommand _setRunway6RCommand;
        RelayCommand _setRunway7LCommand;
        RelayCommand _setRunway7RCommand;
        RelayCommand _setTaxiToGateCommand;
        //RelayCommand _acceptSuggestionCommand;
        RelayCommand _changeSelectedPlaneCommand;
        //RelayCommand _openManualRouteWindowCommand;
        RelayCommand _selectTakeoffCommand;

        #endregion

        #region Button Enablers
        
        // Properties which determine whether a command is enabled
        private bool CanSelect24L { get; set; }
        private bool CanSelect24R { get; set; }
        private bool CanSelect25L { get; set; }
        private bool CanSelect25R { get; set; }
        private bool CanSelect6L { get; set; }
        private bool CanSelect6R { get; set; }
        private bool CanSelect7L { get; set; }
        private bool CanSelect7R { get; set; }
        private bool CanSelectTaxiToGate { get; set; }
        //private bool CanSelectAcceptSuggestion { get; set; }
        private bool CanChangeSelectedPlane { get; set; }
        //private bool CanOpenManualRouteWindow { get; set; }
        private bool CanSelectTakeoff { get; set; }       
        
        #endregion // Button Enablers

        #region Button Command Properties

        public ICommand SetRunway24LCommand
        {
            get
            {
                if (_setRunway24LCommand == null)
                {
                    _setRunway24LCommand = new RelayCommand(
                        param => this.Button24L_Click(),
                        param => this.CanSelect24L
                        );
                }
                return _setRunway24LCommand;
            }
        }

        public ICommand SetRunway24RCommand
        {
            get
            {
                if (_setRunway24RCommand == null)
                {
                    _setRunway24RCommand = new RelayCommand(
                        param => this.Button24R_Click(),
                        param => this.CanSelect24R
                        );
                }
                return _setRunway24RCommand;
            }
        }

        public ICommand SetRunway25LCommand
        {
            get
            {
                if (_setRunway25LCommand == null)
                {
                    _setRunway25LCommand = new RelayCommand(
                        param => this.Button25L_Click(),
                        param => this.CanSelect25L
                        );
                }
                return _setRunway25LCommand;
            }
        }

        public ICommand SetRunway25RCommand
        {
            get
            {
                if (_setRunway25RCommand == null)
                {
                    _setRunway25RCommand = new RelayCommand(
                        param => this.Button25R_Click(),
                        param => this.CanSelect25R
                        );
                }
                return _setRunway25RCommand;
            }
        }

        public ICommand SetRunway6LCommand
        {
            get
            {
                if (_setRunway6LCommand == null)
                {
                    _setRunway6LCommand = new RelayCommand(
                        param => this.Button6L_Click(),
                        param => this.CanSelect6L
                        );
                }
                return _setRunway6LCommand;
            }
        }

        public ICommand SetRunway6RCommand
        {
            get
            {
                if (_setRunway6RCommand == null)
                {
                    _setRunway6RCommand = new RelayCommand(
                        param => this.Button6R_Click(),
                        param => this.CanSelect6R
                        );
                }
                return _setRunway6RCommand;
            }
        }

        public ICommand SetRunway7LCommand
        {
            get
            {
                if (_setRunway7LCommand == null)
                {
                    _setRunway7LCommand = new RelayCommand(
                        param => this.Button7L_Click(),
                        param => this.CanSelect7L
                        );
                }
                return _setRunway7LCommand;
            }
        }

        public ICommand SetRunway7RCommand
        {
            get
            {
                if (_setRunway7RCommand == null)
                {
                    _setRunway7RCommand = new RelayCommand(
                        param => this.Button7R_Click(),
                        param => this.CanSelect7R
                        );
                }
                return _setRunway7RCommand;
            }
        }
        /*
        public ICommand AcceptSuggestionCommand
        {
            get
            {
                if (_acceptSuggestionCommand == null)
                {
                    _acceptSuggestionCommand = new RelayCommand(
                        param => this.ButtonAcceptSuggestedRoute_Click(),
                        param => this.CanSelectAcceptSuggestion
                        );
                }
                return _acceptSuggestionCommand;
            }
        }
        */
        public ICommand ChangeSelectedPlaneCommand
        {
            get
            {
                if (_changeSelectedPlaneCommand == null)
                {
                    _changeSelectedPlaneCommand = new RelayCommand(
                        param => this.ButtonChangeSelectedPlaneCommand_Click(),
                        param => this.CanChangeSelectedPlane
                        );
                }
                return _changeSelectedPlaneCommand;
            }
        }
        /*
        public ICommand OpenManualRouteWindowCommand
        {
            get
            {
                if (_openManualRouteWindowCommand == null)
                {
                    _openManualRouteWindowCommand = new RelayCommand(
                        param => this.ButtonManualRoute_Click(),
                        param => this.CanOpenManualRouteWindow
                        );
                }
                return _openManualRouteWindowCommand;
            }
        }
        */
        
        public ICommand SelectTakeoffCommand
        {
            get
            {
                if (_selectTakeoffCommand == null)
                {
                    _selectTakeoffCommand = new RelayCommand(
                        param => this.ButtonSelectTakeoff_Click(),
                        param => this.CanSelectTakeoff
                        );
                }
                return _selectTakeoffCommand;
            }
        }

        public ICommand SetTaxiToGateCommand
        {
            get
            {
                if (_setTaxiToGateCommand == null)
                {
                    _setTaxiToGateCommand = new RelayCommand(
                        param => this.ButtonSetTaxiToGate_Click(),
                        param => this.CanSelectTaxiToGate
                        );
                }
                return _setTaxiToGateCommand;
            }
        }

        #endregion // Button Commands Properties

        #region Button Command Handlers
        
        public void Button24L_Click()
        {
            SelectedDestinationNode = _surfaceNameToNode["24L"];
            GetSuggestion(SelectedPlane, SelectedDestinationNode, true);
        }       

        public void Button24R_Click()
        {
            SelectedDestinationNode = _surfaceNameToNode["24R"];
            GetSuggestion(SelectedPlane, SelectedDestinationNode, true);
        }

        public void Button25L_Click()
        {
            SelectedDestinationNode = _surfaceNameToNode["25L"];
            GetSuggestion(SelectedPlane, SelectedDestinationNode, true);
        }

        public void Button25R_Click()
        {
            SelectedDestinationNode = _surfaceNameToNode["25R"];
            GetSuggestion(SelectedPlane, SelectedDestinationNode, true);
        }

        public void Button6L_Click()
        {
            SelectedDestinationNode = _surfaceNameToNode["6L"];
            GetSuggestion(SelectedPlane, SelectedDestinationNode, true);
        }

        public void Button6R_Click()
        {
            SelectedDestinationNode = _surfaceNameToNode["6R"];
            GetSuggestion(SelectedPlane, SelectedDestinationNode, true);
        }

        public void Button7L_Click()
        {
            SelectedDestinationNode = _surfaceNameToNode["7L"];
            GetSuggestion(SelectedPlane, SelectedDestinationNode, true);
        }

        public void Button7R_Click()
        {
            SelectedDestinationNode = _surfaceNameToNode["7R"];
            GetSuggestion(SelectedPlane, SelectedDestinationNode, true);
        }

        public void ButtonSetTaxiToGate_Click()
        {
            SelectedDestinationNode = _surfaceNameToNode[SelectedPlane.DestinationGate];
            GetSuggestion(SelectedPlane, SelectedDestinationNode, true);
        }

        public void AcceptSuggestedRoute()
        {
            try
            {
                // If there is more than one Route displayed, the Accept Button shouldn't be enabled
                if (DisplayedRoutes.Count != 1)
                {
                    throw (new Exception("ButtonAcceptSuggestedRoute_Click: More than 1 Route "
                                + "currently displayed. Accept button should be disabled."));
                }
                
                //AcceptRoute(_currentSuggestion);
                // Accept the first Route in DisplayedRoute. There should only be 1 Route displayed.
                AcceptRoute(DisplayedRoutes[0]);
            }
            catch (Exception ex)
            {
                Debug.WriteLine("ButtonAcceptSuggestedRoute_Click: " + ex.Message);
            }
        }
        
        public void ButtonChangeSelectedPlaneCommand_Click()
        {
            Debug.WriteLine("Clicked Plane Icon");
        }
        
        public void SaveManualRouteFromWindow(string manualRouteString)
        {            
            Debug.WriteLine("   Manual Route: " + manualRouteString);
            List<string> routeStrings;

            char[] separators = new char[] { ' ', ',' };
            // Parse taxiway and runway names
            routeStrings = new List<string>(manualRouteString.Split(separators, StringSplitOptions.RemoveEmptyEntries));

            CurrentManualRouteString = routeStrings;

            _manualRouteWindowViewModel.OnRequestClose();

            // Check if the taxiway and/or runway names comprise a legal route
            _airportSvcClient.VerifyRouteString(routeStrings, true);
        }

        public void ButtonSelectTakeoff_Click()
        {
            // This will probably not work as implemented unless planes are initialized
            // to a runway
            switch (NodeToSurfaceName(SelectedPlane.Location))
            {
                case "24L":
                    SelectedDestinationNode = _surfaceNameToNode["6R"];
                    break;
                case "24R":
                    SelectedDestinationNode = _surfaceNameToNode["6L"];
                    break;
                case "25L":
                    SelectedDestinationNode = _surfaceNameToNode["7R"];
                    break;
                case "25R":
                    SelectedDestinationNode = _surfaceNameToNode["7L"];
                    break;
                case "6R":
                    SelectedDestinationNode = _surfaceNameToNode["24L"];
                    break;
                case "6L":
                    SelectedDestinationNode = _surfaceNameToNode["24R"];
                    break;
                case "7R":
                    SelectedDestinationNode = _surfaceNameToNode["25L"];
                    break;
                case "7L":
                    SelectedDestinationNode = _surfaceNameToNode["25R"];
                    break;
            }

            GetSuggestion(SelectedPlane, SelectedDestinationNode, true);
        }

        public void ClearPlaneForTakeoff(int runwayId)
        {
            string runwayName = "";
            switch (runwayId)
            {
                case _runwayId24L:
                    SelectedDestinationNode = _surfaceNameToNode["6R"];
                    runwayName = "24L";
                    break;
                case _runwayId24R:
                    SelectedDestinationNode = _surfaceNameToNode["6L"];
                    runwayName = "24R";
                    break;
                case _runwayId25L:
                    SelectedDestinationNode = _surfaceNameToNode["7R"];
                    runwayName = "25L";
                    break;
                case _runwayId25R:
                    SelectedDestinationNode = _surfaceNameToNode["7L"];
                    runwayName = "25R";
                    break;
            }

            _airportSvcClient.ClearPlaneForTakeoff(SelectedPlane, runwayName);
            GetSuggestion(SelectedPlane, SelectedDestinationNode, false);
        }

        public void ClearPlaneForLanding(int runwayId)
        {
            string runwayName = "";
            switch (runwayId)
            {
                case _runwayId24L:
                    SelectedDestinationNode = _surfaceNameToNode["6R"];
                    runwayName = "24L";
                    break;
                case _runwayId24R:
                    SelectedDestinationNode = _surfaceNameToNode["6L"];
                    runwayName = "24R";
                    break;
                case _runwayId25L:
                    SelectedDestinationNode = _surfaceNameToNode["7R"];
                    runwayName = "25L";
                    break;
                case _runwayId25R:
                    SelectedDestinationNode = _surfaceNameToNode["7L"];
                    runwayName = "25R";
                    break;
            }

            _airportSvcClient.ClearPlaneForLanding(SelectedPlane, runwayName);
            GetSuggestion(SelectedPlane, SelectedDestinationNode, false);
        }

        public void CancelSelectedRoute()
        {
            _airportSvcClient.CancelRoute(_selectedPlane);
        }

        public void LoadScenario()
        {
            _loadScenarioWindowViewModel = new LoadScenarioWindowViewModel(this);
            _loadScenarioWindow = new LoadScenarioWindow();
            _loadScenarioWindowViewModel.RequestClose += (s, e) => _loadScenarioWindow.Close();

            _loadScenarioWindow.DataContext = _loadScenarioWindowViewModel;

            // Show the Manual Route Entry Window
            _loadScenarioWindow.Show();
        }

        public void EnterManualRoute()
        {
            _manualRouteWindowViewModel = new ManualRouteWindowViewModel(this);
            _manualRouteWindow = new ManualRouteWindow();
            _manualRouteWindowViewModel.RequestClose += (s, e) => _manualRouteWindow.Close();

            _manualRouteWindow.DataContext = _manualRouteWindowViewModel;

            // Show the Manual Route Entry Window
            _manualRouteWindow.Show();
        }
        
        #endregion //Button Command Handlers

        #endregion // Buttons

        #region IAirportServiceCallback Implementation

        public void AddNewPotentialIncursion(Incursion incursion)
        {
            Debug.WriteLine("*** Potential Incursion Detected! ***");
            Debug.WriteLine("*** Plane1: " + incursion.PlanesInvolved[0].PlaneFlight.FlightName
                                + " Plane2: " + incursion.PlanesInvolved[1].PlaneFlight.FlightName + " ***");
            Debug.WriteLine("*** RouteNode: (" + incursion.IncursionRouteNode.XPos + ", " + incursion.IncursionRouteNode.YPos + ")");

            //var foundIncursion = from incursion in _incursionList

            // Add received incursion to _incursionList            
            IncursionList.Add(incursion);
        }

        public void IncomingAirportLayout(Map airportMap)
        {
            Debug.WriteLine("** IncomingAirportLayout Called **");

            try
            {
                // Runways
                List<Node> runwayNodeList = new List<Node>();
                List<PathGeometry> runwayPathGeometryList = new List<PathGeometry>();

                AirportMap = airportMap;

                if (_airportMap == null)
                {
                    throw new Exception("_airportMap is null");
                }
                
                foreach (Runway runway in _airportMap.Runways)
                {
                    runwayNodeList.AddRange(runway.Nodes);

                    // Construct Path Geometry for this runway                                        
                    PathGeometry runwayPathGeometry = new PathGeometry();
                    PathFigure runwayPathFigure = new PathFigure();
                    PathFigureCollection runwayPathFigureCollection = new PathFigureCollection();
                    PathSegmentCollection runwayPathSegmentCollection = new PathSegmentCollection();
                    int startX = runway.Nodes[0].XPos;
                    int startY = runway.Nodes[0].YPos;
                    runwayPathFigure.StartPoint = new System.Windows.Point(startX, startY);

                    for (int i = 1; i < runway.Nodes.Count; i++)
                    {
                        LineSegment lineSegment = new LineSegment();
                        lineSegment.Point = new System.Windows.Point(runway.Nodes[i].XPos, runway.Nodes[i].YPos);

                        runwayPathSegmentCollection.Add(lineSegment);
                    }

                    runwayPathFigure.Segments = runwayPathSegmentCollection;
                    runwayPathFigureCollection.Add(runwayPathFigure);

                    runwayPathGeometry.Figures = runwayPathFigureCollection;
                    RunwayPathGeometries.Add(runwayPathGeometry);
                }
                RunwayNodes = new ObservableCollection<Node>(runwayNodeList);

                // Taxiways
                List<Node> taxiwayNodeList = new List<Node>();
                foreach (Taxiway taxiway in _airportMap.Taxiways)
                {
                    taxiwayNodeList.AddRange(taxiway.Nodes);

                    // Construct Path Geometry for this taxiway                                        
                    PathGeometry taxiwayPathGeometry = new PathGeometry();
                    PathFigure taxiwayPathFigure = new PathFigure();
                    PathFigureCollection taxiwayPathFigureCollection = new PathFigureCollection();
                    PathSegmentCollection taxiwayPathSegmentCollection = new PathSegmentCollection();
                    int startX = taxiway.Nodes[0].XPos;
                    int startY = taxiway.Nodes[0].YPos;
                    taxiwayPathFigure.StartPoint = new System.Windows.Point(startX, startY);

                    for (int i = 1; i < taxiway.Nodes.Count; i++)
                    {
                        LineSegment lineSegment = new LineSegment();
                        lineSegment.Point = new System.Windows.Point(taxiway.Nodes[i].XPos, taxiway.Nodes[i].YPos);

                        taxiwayPathSegmentCollection.Add(lineSegment);
                    }

                    taxiwayPathFigure.Segments = taxiwayPathSegmentCollection;
                    taxiwayPathFigureCollection.Add(taxiwayPathFigure);

                    taxiwayPathGeometry.Figures = taxiwayPathFigureCollection;
                    TaxiwayPathGeometries.Add(taxiwayPathGeometry);
                }
                TaxiwayNodes = new ObservableCollection<Node>(taxiwayNodeList);

                // Gates
                List<Node> gateNodeList = new List<Node>();
                foreach (Gate gate in _airportMap.Gates)
                {
                    gateNodeList.AddRange(gate.Nodes);
                }
                GateNodes = new ObservableCollection<Node>(gateNodeList);

            }
            catch (Exception ex)
            {
                Debug.WriteLine("MainPageViewModel: {0}", ex.Message);
            }
        }

        public void IncomingCurrentPlaneList(List<Plane> planeList)
        {
            Debug.WriteLine("** IncomingCurrentPlaneList Called **");

            try
            {
                ActivePlaneList = new ObservableCollection<Plane>(planeList);

                if (_activePlaneList == null)
                {
                    throw new Exception("_activePlaneList is null");
                }
            }
            catch (Exception ex)
            {
                Debug.WriteLine("MainPageViewModel: {0}", ex.Message);
            }
        }

        public void IncomingSuggestion(Route pendingRoute, bool isMitigated)
        {
            Debug.WriteLine("** IncomingSuggestion Called **");

            try
            {
                if (pendingRoute != null)
                {

                    // Update local copy of the updated Flight with the new suggested route
                    //CurrentSuggestion = pendingRoute;
                    ObservableCollection<Route> displayedRoutes = new ObservableCollection<Route>();
                    displayedRoutes.Add(pendingRoute);

                    // Enable Accept button now that a suggestion has been received
                    _manualControlWindowViewModel.CanSelectAcceptSuggestion = true;

                    DisplayedRoutes = displayedRoutes;

                    if (isMitigated)
                    {
                        if (displayedRoutes.Count > 0)
                        {
                            if (displayedRoutes[0].StartTime > DateTime.Now)
                            {
                                DisplayedSuggestionText = "Delay Instruction";
                            }
                            else
                            {
                                DisplayedSuggestionText = "Issue Instruction";
                            }
                        }

                        // Display Suggestion Information Box
                        SuggestionInformationBoxVisibility = true;
                    }
                    else
                    {
                        // Don't display Suggestion Information Box because this is potentially unsafe
                        SuggestionInformationBoxVisibility = false;

                        AcceptRoute(pendingRoute);
                        //AcceptRoute(DisplayedRoutes[0]);
                    }
                }
                else
                {
                    throw (new Exception("Incoming Suggestion is null."));
                }
            }
            catch (Exception ex)
            {
                Debug.WriteLine("MainPageViewModel: {0}", ex.Message);
            }
        }

        public void IncomingScenarioList(List<Scenario> scenarios)
        {
            _airportScenarios = scenarios;

            _manualControlWindowViewModel.CanOpenLoadScenarioWindow = true;
            //OnPropertyChanged("OpenLoadScenarioWindowCommand");
        }

        public void newFlightUpdate(Flight flight)
        {
            Debug.WriteLine("** newFlightUpdate Called **");
        }

        public void PlanePositionUpdate(int planeId, Node newPosition)
        {
            Debug.WriteLine("** PlanePositionUpdate Called **");
        }

        public void RemovePotentialIncursion(Incursion incursion)
        {
            bool successful = false;

            for (int i = 0; i < _incursionList.Count; i++)
            {
                if (_incursionList[i].IncusionId == incursion.IncusionId)
                {
                    IncursionList.RemoveAt(i);
                    successful = true;
                    break;
                }
            }

            Debug.WriteLineIf(successful, "*** Potential Incursion Removed ***");
            Debug.WriteLineIf(!successful, "*** Failed to Remove Potential Incursion ***");
        }        

        public void UpdatePlane(Plane updatedPlane)
        {
            Debug.WriteLine("** UpdatePlane Called **");

            try
            {                
                switch (updatedPlane.UpdateType)
                {
                    case PlaneUpdateType.AddNewPlane:
                        ActivePlaneList.Add(updatedPlane);
                        /*
                        if (updatedPlane.PlaneFlight != null)
                        {
                            FlightList.Add(updatedPlane.PlaneFlight);
                        }
                        */
                        break;

                    case PlaneUpdateType.UpdateExistingPlane:
                        for (int i = 0; i < ActivePlaneList.Count; i++)
                        {
                            if (ActivePlaneList[i].PlaneId == updatedPlane.PlaneId)
                            {                                   
                                //ActivePlaneList[i] = updatedPlane;
                                //ActivePlaneList[i].Airspeed = updatedPlane.Airspeed;
                                //ActivePlaneList[i].Altitude = updatedPlane.Altitude;
                                //ActivePlaneList[i].BufferZone = updatedPlane.BufferZone;
                                ActivePlaneList[i].CurrentEdge = updatedPlane.CurrentEdge;
                                ActivePlaneList[i].CurrentRoute = updatedPlane.CurrentRoute;
                                ActivePlaneList[i].DestinationNode = updatedPlane.DestinationNode;
                                ActivePlaneList[i].Heading = updatedPlane.Heading;
                                ActivePlaneList[i].Location = updatedPlane.Location;
                                ActivePlaneList[i].NextRouteNodeIndex = updatedPlane.NextRouteNodeIndex;
                                ActivePlaneList[i].PlaneFlight = updatedPlane.PlaneFlight;
                                ActivePlaneList[i].PositionVector = updatedPlane.PositionVector;
                                ActivePlaneList[i].VelocityVector = updatedPlane.VelocityVector;
                                ActivePlaneList[i].Name = updatedPlane.Name;

                                if (SelectedPlane != null)
                                {
                                    // If the updated plane is currently selected, update SelectedPlane
                                    if (SelectedPlane.PlaneId == ActivePlaneList[i].PlaneId)
                                    {
                                        SelectedPlane = ActivePlaneList[i];
                                    }
                                }
                                break;
                            }
                        }
                        break;

                    case PlaneUpdateType.DeletePlane:
                        // TODO Implement Delete functionality
                        break;

                    default:
                        break;
                }

                /*
                // Update the plane in FlightList
                // TODO Be able to handle plane without an associated Plane
                for (int j = 0; j < FlightList.Count; j++)
                {
                    if (FlightList[j].FlightPlane.PlaneId == updatedPlane.PlaneId)
                    {
                        FlightList[j].FlightPlane = updatedPlane;
                    }
                }
                */

                
            }
            catch (Exception ex)
            {
                Debug.WriteLine("MainPageViewModel: {0}", ex.Message);
            }
        }

        public void RouteStringVerificationFailed(List<string> routeStrings)
        {

        }

        #endregion // IAirportServiceCallback Implementation

        #region AirportService RPC Callers
        
        private void RegisterForPlaneUpdates()
        {
            Debug.WriteLine("** AirportServiceAgent: RegisterForPlaneUpdates **");
            _airportSvcClient.RegisterForPlaneUpdates();
        }

        private void UnregisterForPlaneUpdates()
        {
            Debug.WriteLine("** AirportServiceAgent: UnregisterForPlaneUpdates **");
            _airportSvcClient.UnregisterForPlaneUpdates();
        }

        private void RegisterForIncursionDetectedUpdates()
        {
            Debug.WriteLine("** AirportServiceAgent: RegisterForIncursionDetectedUpdates **");
            _airportSvcClient.RegisterForIncursionDetectedUpdates();
        }

        private void UnregisterForIncursionDetectedUpdates()
        {
            Debug.WriteLine("** AirportServiceAgent: UnregisterForIncursionDetectedUpdates **");
            _airportSvcClient.UnregisterForIncursionDetectedUpdates();
        }
                
        private void GetAirportLayout()
        {
            Debug.WriteLine("** AirportServiceAgent: GetAirportLayout **");
            _airportSvcClient.GetAirportLayout();
        }
        
        private void GetCurrentPlaneList()
        {            
            Debug.WriteLine("** AirportServiceAgent: GetCurrentPlaneList **");
            _airportSvcClient.GetCurrentPlaneList();
        }

        private void GetScenarioList()
        {
            Debug.WriteLine("** AirportServiceAgent: GetScenarioList **");
            _airportSvcClient.GetScenarioList();
        }

        public void LoadScenario(int scenarioId)
        {
            try
            {
                Debug.WriteLine("** AirportServiceAgent: LoadScenario **");

                _airportSvcClient.LoadScenario(scenarioId);
            }
            catch (Exception ex)
            {
                Debug.WriteLine("LoadScenario: " + ex.Message);
            }
        }

        private void GetSuggestion(Plane plane, Node destinationNode, bool returnMitigation)
        {
            try
            {
                _airportSvcClient.GetSuggestion(plane, destinationNode, returnMitigation);
            }
            catch (Exception ex)
            {
                Debug.WriteLine("MainPageViewModel: {0}", ex.Message);
            }
        }
        
        private void AcceptRoute(Route acceptedRoute)
        {
            try
            {
                acceptedRoute.RoutePlane.DestinationNode = SelectedDestinationNode;
                _airportSvcClient.AcceptRoute(acceptedRoute);
            }
            catch (Exception ex)
            {
                Debug.WriteLine("MainPageViewModel: {0}", ex.Message);
            }
        }
        
        #endregion //AirportService RPC Callers

        #region Helper Methods

        private void InitializeSurfaceNameLists()
        {
            _nodeToSurfaceName = new Dictionary<Node, string>();
            _surfaceNameToNode = new Dictionary<string, Node>();

            Node runwayNode = new Node();
            runwayNode.XPos = 624;
            runwayNode.YPos = 83;
            runwayNode.NodeId = -1;
            _surfaceNameToNode.Add("24L", runwayNode);
            _nodeToSurfaceName.Add(runwayNode, "24L");

            runwayNode = new Node();
            runwayNode.XPos = 618;
            runwayNode.YPos = 42;
            runwayNode.NodeId = -1;
            _surfaceNameToNode.Add("24R", runwayNode);
            _nodeToSurfaceName.Add(runwayNode, "24R");

            runwayNode = new Node();
            runwayNode.XPos = 959;
            runwayNode.YPos = 359;
            runwayNode.NodeId = -1;
            _surfaceNameToNode.Add("25L", runwayNode);
            _nodeToSurfaceName.Add(runwayNode, "25L");

            runwayNode = new Node();
            runwayNode.XPos = 1012;
            runwayNode.YPos = 306;
            runwayNode.NodeId = -1;
            _surfaceNameToNode.Add("25R", runwayNode);
            _nodeToSurfaceName.Add(runwayNode, "25R");

            runwayNode = new Node();
            runwayNode.XPos = 105;
            runwayNode.YPos = 106;
            runwayNode.NodeId = -1;
            _surfaceNameToNode.Add("6L", runwayNode);
            _nodeToSurfaceName.Add(runwayNode, "6L");

            runwayNode = new Node();
            runwayNode.XPos = 38;
            runwayNode.YPos = 154;
            runwayNode.NodeId = -1;
            _surfaceNameToNode.Add("6R", runwayNode);
            _nodeToSurfaceName.Add(runwayNode, "6R");

            runwayNode = new Node();
            runwayNode.XPos = 317;
            runwayNode.YPos = 390;
            runwayNode.NodeId = -1;
            _surfaceNameToNode.Add("7L", runwayNode);
            _nodeToSurfaceName.Add(runwayNode, "7L");

            runwayNode = new Node();
            runwayNode.XPos = 323;
            runwayNode.YPos = 437;
            runwayNode.NodeId = -1;
            _surfaceNameToNode.Add("7R", runwayNode);
            _nodeToSurfaceName.Add(runwayNode, "7R");

            // Initialize Gates
            Node gateNode = new Node();
            gateNode.XPos = 658;
            gateNode.YPos = 165;
            gateNode.NodeId = _gateIdD7;
            _surfaceNameToNode.Add("D7", gateNode);
            _nodeToSurfaceName.Add(gateNode, "D7");

            gateNode = new Node();
            gateNode.XPos = 616;
            gateNode.YPos = 174;
            gateNode.NodeId = _gateIdD8;
            _surfaceNameToNode.Add("D8", gateNode);
            _nodeToSurfaceName.Add(gateNode, "D8");

            gateNode = new Node();
            gateNode.XPos = 557;
            gateNode.YPos = 181;
            gateNode.NodeId = _gateIdD9;
            _surfaceNameToNode.Add("D9", gateNode);
            _nodeToSurfaceName.Add(gateNode, "D9");

            gateNode = new Node();
            gateNode.XPos = 499;
            gateNode.YPos = 188;
            gateNode.NodeId = _gateIdD10;
            _surfaceNameToNode.Add("D10", gateNode);
            _nodeToSurfaceName.Add(gateNode, "D10");

            gateNode = new Node();
            gateNode.XPos = 684;
            gateNode.YPos = 250;
            gateNode.NodeId = _gateIdC6;
            _surfaceNameToNode.Add("C6", gateNode);
            _nodeToSurfaceName.Add(gateNode, "C6");

            gateNode = new Node();
            gateNode.XPos = 640;
            gateNode.YPos = 257;
            gateNode.NodeId = _gateIdC7;
            _surfaceNameToNode.Add("C7", gateNode);
            _nodeToSurfaceName.Add(gateNode, "C7");

            gateNode = new Node();
            gateNode.XPos = 598;
            gateNode.YPos = 260;
            gateNode.NodeId = _gateIdC8;
            _surfaceNameToNode.Add("C8", gateNode);
            _nodeToSurfaceName.Add(gateNode, "C8");

            gateNode = new Node();
            gateNode.XPos = 556;
            gateNode.YPos = 265;
            gateNode.NodeId = _gateIdC9;
            _surfaceNameToNode.Add("C9", gateNode);
            _nodeToSurfaceName.Add(gateNode, "C9");

            gateNode = new Node();
            gateNode.XPos = 512;
            gateNode.YPos = 271;
            gateNode.NodeId = _gateIdC10;
            _surfaceNameToNode.Add("C10", gateNode);
            _nodeToSurfaceName.Add(gateNode, "C10");
        }

        private string NodeToSurfaceName(Node node)
        {
            if (node.XPos == 624 && node.YPos == 83)
            {
                return "24L";
            }

            if (node.XPos == 618 && node.YPos == 42)
            {
                return "24R";
            }

            if (node.XPos == 959 && node.YPos == 359)
            {
                return "25L";
            }

            if (node.XPos == 1012 && node.YPos == 306)
            {
                return "25R";
            }

            if (node.XPos == 105 && node.YPos == 106)
            {
                return "6L";
            }

            if (node.XPos == 38 && node.YPos == 154)
            {
                return "6R";
            }

            if (node.XPos == 317 && node.YPos == 390)
            {
                return "7L";
            }

            if (node.XPos == 323 && node.YPos == 437)
            {
                return "7R";
            }

            if (node.XPos == 512 && node.YPos == 271)
            {
                return "C10";
            }

            return "";
        }

        #endregion
    }    

    // Class to bind the canvas position to xPos and yPos of each map Node
    public class MapNodesItemsControl : ItemsControl
    {
        protected override void PrepareContainerForItemOverride(DependencyObject element, object item)
        {            
            FrameworkElement contentitem = element as FrameworkElement;
            Binding leftBinding = new Binding("XPos");
            Binding topBinding = new Binding("YPos");
            contentitem.SetBinding(Canvas.LeftProperty, leftBinding);
            contentitem.SetBinding(Canvas.TopProperty, topBinding);
            base.PrepareContainerForItemOverride(element, item);             
        }
    }

    public class PlaneIconsItemsControl : ItemsControl
    {
        protected override void PrepareContainerForItemOverride(DependencyObject element, object item)
        {            
            try
            {
                FrameworkElement contentitem = element as FrameworkElement;
                //Binding leftBinding = new Binding("Location.XPos");
                //Binding topBinding = new Binding("Location.YPos");
                Binding leftBinding = new Binding("PositionVector.X");
                Binding topBinding = new Binding("PositionVector.Y");
                leftBinding.Converter = new FloatToIntConverter();
                topBinding.Converter = new FloatToIntConverter();

                contentitem.SetBinding(Canvas.LeftProperty, leftBinding);
                contentitem.SetBinding(Canvas.TopProperty, topBinding);

                base.PrepareContainerForItemOverride(element, item);
            }
            catch (Exception ex)
            {
                Debug.WriteLine("MainPageViewModel: {0}", ex.Message);
            }
        }
    }

}
